package edu.hawaii.myisern.action;

import java.util.ArrayList;
import java.util.List;
import edu.hawaii.myisern.model.MyIsernModel;
import edu.hawaii.myisern.organizations.jaxb.AffiliatedResearchers;
import edu.hawaii.myisern.organizations.jaxb.Organization;
import edu.hawaii.myisern.organizations.jaxb.ResearchKeywords;
import edu.hawaii.myisern.researchers.jaxb.Researcher;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;

/**
 * Allows for a organization to be added or edited.
 * 
 * @author Ka Yee Leung
 * @author Ivan Wu
 * @author Chiao-Fen Zielinski-Liu
 * @author Michal Zielinski
 */
public class OrganizationActionBean implements ActionBean {
  /** Required by the ActionBean interface. */
  private ActionBeanContext context;

  /** An error string, always displayed, but invisible if empty. */
  private String errorMessage = "";

  /** Add label and type. */
  private String addType;

  /** Edit label and type. */
  private String editType;

  /** Added? */
  private boolean added;

  /** Add new Organization */
  private boolean addNewOrganization = false;
  
  /** Add new organization from within new Collaboration */
  private boolean addNewColOrganization = false;

  /** Editing? */
  private boolean editing;

  /** Edited? */
  private boolean edited;

  /** The single MyIsern instance manipulated by all webapp users. */
  private MyIsernModel myIsern = MyIsernModel.getInstance();

  /** Researcher attributes */
  private String name;
  private String orgName;
  private String type;
  private String contact;
  private String affiliatedResearchers;
  private String country;
  private String researchKeywords;
  private String researchDescription;
  private String homePage;

  private String organization = "Organization";
  private List<String> organizationNames;
  private List<String> researcherNames;
  private List<String> selectedAffiliatedResearcherNames;
  private List<String> editSelectedAffiliatedResearcherNames;
  private String home = "/home.jsp";
  private String blank = "---Leave Blank---";

  /**
   * Returns the context. Required by the interface.
   * 
   * @return the ActionBeanContext.
   */
  public ActionBeanContext getContext() {
    return context;
  }

  /**
   * Sets the context. Required by the interface.
   * 
   * @param context
   *          The ActionBeanContext to set.
   */
  public void setContext(ActionBeanContext context) {
    this.context = context;
  }

  /**
   * Returns the error message, which may be empty. Indicates if an error was
   * made adding or editing the organization.
   * 
   * @return The error message.
   */
  public String getErrorMessage() {
    return this.errorMessage;
  }

  /**
   * Returns the appropriate add label.
   * 
   * @return The add label.
   */
  public String getAddType() {
    return this.addType;
  }

  /**
   * Returns the appropriate edit label.
   * 
   * @return The edit label.
   */
  public String getEditType() {
    return this.editType;
  }

  /**
   * Returns the whether the organization has been added or not.
   * 
   * @return Whether the organization has been added or not.
   */
  public boolean getAdded() {
    return this.added;
  }

  /**
   * Returns the whether the organization has been edited or not.
   * 
   * @return Whether the organization has been edited or not.
   */
  public boolean getEdited() {
    return this.edited;
  }

  /**
   * Returns whether the organization is being edited or not.
   * 
   * @return Whether the organization is being edited or not.
   */
  public boolean getEditing() {
    return this.editing;
  }
  
  /**
   * Adding new organization from within researcher.
   * 
   * @return true adding new organization otherwise false.
   */
  public boolean getAddNewOrganization() {
    return this.addNewOrganization;
  }
  
  /**
   * Adding new organization from within collaboration.
   * 
   * @return true adding new organization otherwise false.
   */
  public boolean getAddNewColOrganization() {
    return this.addNewColOrganization;
  }
  
  /**
   * Creates and returns the list of organization names.
   * 
   * @return The list of organization names.
   */
  public List<String> getOrganizationNames() {
    List<Organization> orgList = myIsern.getOrganizationsDB();
    List<String> orgNamesList = new ArrayList<String>();
    for (Organization org : orgList) {
      orgNamesList.add(org.getName());
    }
    this.organizationNames = orgNamesList;
    return this.organizationNames;
  }

  /**
   * Creates and returns the list of researcher names.
   * 
   * @return The list of organization names.
   */
  public List<String> getResearcherNames() {
    List<Researcher> resList = myIsern.getResearchersDB();
    List<String> resNamesList = new ArrayList<String>();
    resNamesList.add(blank);
    for (Researcher res : resList) {
      resNamesList.add(res.getName());
    }
    this.researcherNames = resNamesList;
    return this.researcherNames;
  }

  /**
   * Sets the names of the selected affiliated researchers.
   * 
   * @param selectedAffiliatedResearcherNames
   *          The selected names list.
   */
  public void setSelectedAffiliatedResearcherNames(
      List<String> selectedAffiliatedResearcherNames) {
    this.selectedAffiliatedResearcherNames = selectedAffiliatedResearcherNames;
  }

  /**
   * Returns the name of the selected affiliated researchers.
   * 
   * @return The name of the selected affiliated researchers.
   */
  public List<String> getSelectedAffiliatedResearcherNames() {
    return this.selectedAffiliatedResearcherNames;
  }
  
  /**
   * Sets the names of the selected affiliated researchers to remove.
   * @param editSelectedAffiliatedResearcherNames The editing names.
   */
  
  public void setEditSelectedAffiliatedResearcherNames (
      List<String> editSelectedAffiliatedResearcherNames) {
    this.editSelectedAffiliatedResearcherNames = editSelectedAffiliatedResearcherNames;
  }

  /**
   * Returns the name of the modfied selected affiliated researchers.
   * 
   * @return The name of the selected affiliated researchers.
   */
  public List<String> getEditSelectedAffiliatedResearcherNames() {
    return this.editSelectedAffiliatedResearcherNames;
  }

  /**
   * Displays the form to add a organization.
   * 
   * @return A Resolution indicating to redisplay the add.jsp page.
   */
  public Resolution organizationForm() {
    this.addType = organization;
    return new ForwardResolution(home);
  }

  /**
   * Displays the form to edit an organization.
   * 
   * @return A Resolution indicating to redisplay the edit.jsp page.
   */
  public Resolution editOrganizationForm() {
    this.editType = organization;
    return new ForwardResolution(home);
  }
  
  /**
   * Sets the name of the organization when added is true.
   * 
   * @param name
   *          The name to set.
   */
  public void setName(String name) {
    this.name = name.trim();
  }

  /**
   * Returns the name of the organization when added is true.
   * 
   * @return The name of the organization.
   */
  public String getName() {
    return this.name;
  }
  
  /**
   * Sets the name of the organization when adding from within researcher or collaboration.
   * 
   * @param orgName The name to set.
   */
  public void setOrgName(String orgName) {
    this.orgName = orgName.trim();
  }

  /**
   * Returns the name of the organization when adding from within researcher or collaboration.
   * 
   * @return The name of the organization.
   */
  public String getOrgName() {
    return this.orgName;
  }

  /**
   * Sets the type of the organization.
   * 
   * @param type
   *          The type to set.
   */
  public void setType(String type) {
    this.type = type.trim();
  }

  /**
   * Returns the type of the organization.
   * 
   * @return The type of the organization.
   */
  public String getType() {
    return this.type;
  }

  /**
   * Sets the contact of the organization.
   * 
   * @param contact
   *          The contact to set.
   */
  public void setContact(String contact) {
    this.contact = contact.trim();
  }

  /**
   * Returns the contact of the organization.
   * 
   * @return The contact of the organization.
   */
  public String getContact() {
    return this.contact;
  }

  /**
   * Sets the affiliated researchers of the organization.
   * 
   * @param affiliatedResearchers
   *          The researchers to set.
   */
  public void setAffiliatedResearchers(String affiliatedResearchers) {
    this.affiliatedResearchers = affiliatedResearchers;
  }

  /**
   * Returns the affiliated researchers of the organization.
   * 
   * @return The affiliated researchers of the organization.
   */
  public String getAffiliatedResearchers() {
    return this.affiliatedResearchers;
  }
  
  /**
   * Sets the country of the organization.
   * 
   * @param country
   *          The country to set.
   */
  public void setCountry(String country) {
    this.country = country.trim();
  }

  /**
   * Returns the country of the organization.
   * 
   * @return The country of the organization.
   */
  public String getCountry() {
    return this.country;
  }

  /**
   * Sets the research keywords of the organization.
   * 
   * @param researchKeywords
   *          The keywords to set.
   */
  public void setResearchKeywords(String researchKeywords) {
    this.researchKeywords = researchKeywords;
  }

  /**
   * Returns the research keywords of the organization.
   * 
   * @return The research keywords of the organization.
   */
  public String getResearchKeywords() {
    return this.researchKeywords;
  }

  /**
   * Sets the research description of the organization.
   * 
   * @param researchDescription
   *          The research description to set.
   */
  public void setResearchDescription(String researchDescription) {
    this.researchDescription = researchDescription.trim();
  }

  /**
   * Returns the research description of the organization.
   * 
   * @return The research description of the organization.
   */
  public String getResearchDescription() {
    return this.researchDescription;
  }

  /**
   * Sets the home page of the organization.
   * 
   * @param homePage
   *          The home page to set.
   */
  public void setHomePage(String homePage) {
    this.homePage = homePage.trim();
  }

  /**
   * Returns the home page of the organization.
   * 
   * @return The home page of the organization.
   */
  public String getHomePage() {
    return this.homePage;
  }

  /**
   * Adds a organization.
   * 
   * @return A Resolution indicating to redisplay the add.jsp page.
   * @throws Exception
   *           If problems occur.
   */
  public Resolution add() throws Exception {
    if ((this.orgName == null) || ("".equals(this.orgName))) {
      this.errorMessage = "Please enter a name.";
      this.addType = organization;
    }
    else if (this.getSelectedAffiliatedResearcherNames() == null) {
      this.errorMessage = "Please select an Affiliated Researcher";
      this.addType = organization;
    }
    else {
      List<Organization> list = myIsern.getOrganizationsDB();
      boolean found = false;
      for (Organization organization : list) {
        if (organization.getName().equals(this.orgName.replace('_', ' '))) {
          found = true;
        }
      }

      if (found) {
        this.errorMessage = "Organization already exists. Please edit.";
        this.editType = organization;
        this.editing = true;
        this.name = this.orgName;
      } 
      else {
        Organization newOrganization = new Organization();
        newOrganization.setName(this.orgName);
        newOrganization.setType(this.type);
        newOrganization.setContact(this.contact);
        AffiliatedResearchers newAffiliatedResearchers = new AffiliatedResearchers();
        if (this.getSelectedAffiliatedResearcherNames().contains(blank)) {
          this.getSelectedAffiliatedResearcherNames().remove(blank);
          this.getSelectedAffiliatedResearcherNames().add("");
        }
        newAffiliatedResearchers.getAffiliatedResearcher().addAll(
            this.getSelectedAffiliatedResearcherNames());
        newOrganization.setAffiliatedResearchers(newAffiliatedResearchers);
        newOrganization.setCountry(this.country);
        ResearchKeywords newResearchKeywords = new ResearchKeywords();
        newResearchKeywords.getResearchKeyword().addAll(
            myIsern.createList(this.researchKeywords));
        newOrganization.setResearchKeywords(newResearchKeywords);
        newOrganization.setResearchDescription(this.researchDescription);
        newOrganization.setHomePage(this.homePage);

        // myIsern.addOrganization(newOrganization);
        myIsern.addOrganizationDB(newOrganization);
        this.name = this.orgName;
        this.added = true;
      }
    }
    // this.addType = organization;
    return new ForwardResolution(home);
  }

  /**
   * Adds an organization when the new organization link within new Researcher is clicked.
   * 
   * @return A Resolution indicating to redisplay the home.jsp page with the researcher form.
   * @throws Exception If problems occur.
   */
  public Resolution addOrgAndRes() throws Exception {
    if ((this.orgName == null) || ("".equals(this.orgName))) {
      this.errorMessage = "Please enter a name.";
      this.addType = organization;
      this.addNewOrganization = true;
    } 
    else if (this.getSelectedAffiliatedResearcherNames() == null) {
      this.errorMessage = "Please select an Affiliated Researcher";
      this.addType = organization;
      this.addNewOrganization = true;
    }
    else {
      List<Organization> list = myIsern.getOrganizationsDB();
      boolean found = false;
      for (Organization organization : list) {
        if (organization.getName().equals(this.orgName.replace('_', ' '))) {
          found = true;
        }
      }

      if (found) {
        this.errorMessage = "Organization already exists. Please edit.";
        this.editType = organization;
        this.editing = true;
        this.name = this.orgName;
      } 
      else {
        Organization newOrganization = new Organization();
        newOrganization.setName(this.orgName);
        newOrganization.setType(this.type);
        newOrganization.setContact(this.contact);
        AffiliatedResearchers newAffiliatedResearchers = new AffiliatedResearchers();
        if (this.getSelectedAffiliatedResearcherNames().contains(blank)) {
          this.getSelectedAffiliatedResearcherNames().remove(blank);
          this.getSelectedAffiliatedResearcherNames().add("");
        }
        newAffiliatedResearchers.getAffiliatedResearcher().addAll(
            this.getSelectedAffiliatedResearcherNames());
        newOrganization.setAffiliatedResearchers(newAffiliatedResearchers);
        newOrganization.setCountry(this.country);
        ResearchKeywords newResearchKeywords = new ResearchKeywords();
        newResearchKeywords.getResearchKeyword().addAll(
            myIsern.createList(this.researchKeywords));
        newOrganization.setResearchKeywords(newResearchKeywords);
        newOrganization.setResearchDescription(this.researchDescription);
        newOrganization.setHomePage(this.homePage);

        // myIsern.addOrganization(newOrganization);
        myIsern.addOrganizationDB(newOrganization);
        this.addType = "Researcher";
      }
    }
    return new ForwardResolution(home);
  }

  /**
   * Adds an organization when the new organization link within new Researcher is clicked.
   * 
   * @return A Resolution indicating to redisplay the home.jsp page with the researcher form.
   * @throws Exception If problems occur.
   */
  public Resolution addOrgAndCol() throws Exception {
    if ((this.orgName == null) || ("".equals(this.orgName))) {
      this.errorMessage = "Please enter a name.";
      this.addType = organization;
      this.addNewColOrganization = true;
    } 
    else if (this.getSelectedAffiliatedResearcherNames() == null) {
      this.errorMessage = "Please select an Affiliated Researcher";
      this.addType = organization;
      this.addNewColOrganization = true;
    }
    else {
      List<Organization> list = myIsern.getOrganizationsDB();
      boolean found = false;
      for (Organization organization : list) {
        if (organization.getName().equals(this.orgName.replace('_', ' '))) {
          found = true;
        }
      }

      if (found) {
        this.errorMessage = "Organization already exists. Please edit.";
        this.editType = organization;
        this.editing = true;
        this.name = this.orgName;
      } 
      else {
        Organization newOrganization = new Organization();
        newOrganization.setName(this.orgName);
        newOrganization.setType(this.type);
        newOrganization.setContact(this.contact);
        AffiliatedResearchers newAffiliatedResearchers = new AffiliatedResearchers();
        if (this.getSelectedAffiliatedResearcherNames().contains(blank)) {
          this.getSelectedAffiliatedResearcherNames().remove(blank);
          this.getSelectedAffiliatedResearcherNames().add("");
        }
        newAffiliatedResearchers.getAffiliatedResearcher().addAll(
            this.getSelectedAffiliatedResearcherNames());
        newOrganization.setAffiliatedResearchers(newAffiliatedResearchers);
        newOrganization.setCountry(this.country);
        ResearchKeywords newResearchKeywords = new ResearchKeywords();
        newResearchKeywords.getResearchKeyword().addAll(
            myIsern.createList(this.researchKeywords));
        newOrganization.setResearchKeywords(newResearchKeywords);
        newOrganization.setResearchDescription(this.researchDescription);
        newOrganization.setHomePage(this.homePage);

        // myIsern.addOrganization(newOrganization);
        myIsern.addOrganizationDB(newOrganization);
        this.addType = "Collaboration";
      }
    }
    return new ForwardResolution(home);
  }
  
  /**
   * Displays the information to edit.
   * 
   * @return A resolution indicating to redisplay the edit.jsp page.
   * @throws Exception
   *           If problems occur.
   */
  public Resolution displayEdit() throws Exception {
    List<Organization> list = myIsern.getOrganizationsDB();
    Organization editOrganization = new Organization();
    boolean found = false;
    for (Organization organization : list) {
      if (organization.getName().equals(this.name.replace('_', ' '))) {
        editOrganization = organization;
        found = true;
      }
    }

    if (found) {
      this.type = editOrganization.getType();
      this.contact = editOrganization.getContact();
      this.selectedAffiliatedResearcherNames = editOrganization
          .getAffiliatedResearchers().getAffiliatedResearcher();
      this.country = editOrganization.getCountry();
      this.researchKeywords = myIsern.createListString(editOrganization
          .getResearchKeywords().getResearchKeyword());
      this.researchDescription = editOrganization.getResearchDescription();
      this.homePage = editOrganization.getHomePage();

      this.editing = true;
    }

    this.editType = organization;
    return new ForwardResolution(home);
  }

  /**
   * Edits a organization.
   * 
   * @return A resolution indicating to redisplay the edit.jsp page.
   * @throws Exception
   *           If problems occur.
   */
  public Resolution edit() throws Exception {
    List<Organization> list = myIsern.getOrganizationsDB();
    // int count = 0;
    Organization editOrganization = new Organization();
    for (Organization organization : list) {
      if (organization.getName().equals(this.name.replace('_', ' '))) {
        editOrganization = organization;
        // count = list.indexOf(organization);
      }
    }

    editOrganization.setName(this.name);
    editOrganization.setType(this.type);
    editOrganization.setContact(this.contact);
    editOrganization.setCountry(this.country);
    ResearchKeywords newResearchKeywords = new ResearchKeywords();
    newResearchKeywords.getResearchKeyword().addAll(
        myIsern.createList(this.researchKeywords));
    editOrganization.setResearchKeywords(newResearchKeywords);
    editOrganization.setResearchDescription(this.researchDescription);
    editOrganization.setHomePage(this.homePage);

    myIsern.editOrganizationDB(editOrganization);

    this.edited = true;
    this.editing = true;
    // this.editType = organization;
    return new ForwardResolution(home);
  }

  /**
   * Removes the organization.
   * 
   * @return A resolution indicating to redisplay the add.jsp or edit.jsp page.
   * @throws Exception
   *           If problems occur.
   */
  public Resolution remove() throws Exception {
    myIsern.removeOrganizationDB(this.name);

    this.errorMessage = this.name + " has been deleted.";
    return new ForwardResolution(home);
  }
  
  /**
   * Sets the addType to Organization when adding from within researcher.
   * 
   * @return Resolution redisplaying home.jsp to add Organization.
   * @throws Exception if problems occur.
   */
  public Resolution newOrganization() throws Exception {
    this.addType = "Organization";
    this.addNewOrganization = true;
    return new ForwardResolution(home);
  }
  
  /**
   * Sets the addType to Organization when adding from within collaboration.
   * 
   * @return Resolution redisplaying home.jsp to add Organization.
   * @throws Exception if problems occur.
   */
  public Resolution newColOrganization() throws Exception {
    this.addType = "Organization";
    this.addNewColOrganization = true;
    return new ForwardResolution(home);
  }
  
  /**
   * Deletes the selected affiliated researcher when editing organizations.
   * 
   * @return redisplay home.jsp.
   */
  public Resolution editSelectedAffRes() {
    List<Organization> list = myIsern.getOrganizationsDB();
    Organization editOrganization = new Organization();

    for (Organization organization : list) {
      if (organization.getName().equals(this.name.replace('_', ' '))) {
        editOrganization = organization;
      }
    }
    if (this.affiliatedResearchers == null) {
      this.affiliatedResearchers = "";
    }
    editOrganization.getAffiliatedResearchers().
    getAffiliatedResearcher().remove(this.affiliatedResearchers);
    this.selectedAffiliatedResearcherNames = 
      editOrganization.getAffiliatedResearchers().getAffiliatedResearcher();
    myIsern.editOrganizationDB(editOrganization);
    this.editType = organization;
    this.editing = true;
    return new ForwardResolution(home);
  }
  
  /**
   * Adds the selected affiliated researcher when editing organizations.
   * 
   * @return redisplay home.jsp.
   */
  public Resolution addSelectedAffRes() {
    List<Organization> list = myIsern.getOrganizationsDB();
    Organization editOrganization = new Organization();

    for (Organization organization : list) {
      if (organization.getName().equals(this.name.replace('_', ' '))) {
        editOrganization = organization;
      }
    }
    if ((this.orgName == null) || (blank.equals(orgName))) {
      this.orgName = "";
    }
    editOrganization.getAffiliatedResearchers().getAffiliatedResearcher().add(this.orgName);
    this.selectedAffiliatedResearcherNames = 
      editOrganization.getAffiliatedResearchers().getAffiliatedResearcher();
    myIsern.editOrganizationDB(editOrganization);
    this.editType = organization;
    this.editing = true;
    return new ForwardResolution(home);
  }
}
